M=require("ming_node");
/**
 * serialport@10.4.0
 */
const { SerialPort } = require('serialport')



class ModbusRtuRequest{
     reqBuffer;//原始的请求数组
     slaveAddress; //从机地址
     funcCode;
     startAddress;
     len; //读取数量
     status=0;
     totalByte; //总字节数量
}
class MB_ENUM{
    static MB_ADDRESS_BROADCAST =   ( 0 )   /*! Modbus broadcast address. */
    static MB_ADDRESS_MIN =          ( 1 )   /*! Smallest possible slave address. */
    static MB_ADDRESS_MAX =          ( 247 ) /*! Biggest possible slave address. */
    static MB_FUNC_NONE  =                         (  0 )
    static MB_FUNC_READ_COILS  =                   (  1 )
    static MB_FUNC_READ_DISCRETE_INPUTS=           (  2 )
    static MB_FUNC_WRITE_SINGLE_COIL =             (  5 )
    static MB_FUNC_WRITE_MULTIPLE_COILS =          ( 15 )
    static MB_FUNC_READ_HOLDING_REGISTER =         (  3 )
    static MB_FUNC_READ_INPUT_REGISTER  =          (  4 )
    static MB_FUNC_WRITE_REGISTER    =             (  6 )
    static MB_FUNC_WRITE_MULTIPLE_REGISTERS =      ( 16 )
    static MB_FUNC_READWRITE_MULTIPLE_REGISTERS=   ( 23 )
    static MB_FUNC_DIAG_READ_EXCEPTION =           (  7 )
    static MB_FUNC_DIAG_DIAGNOSTIC  =              (  8 )
    static MB_FUNC_DIAG_GET_COM_EVENT_CNT =        ( 11 )
    static MB_FUNC_DIAG_GET_COM_EVENT_LOG =        ( 12 )
    static MB_FUNC_OTHER_REPORT_SLAVEID  =         ( 17 )
    static MB_FUNC_ERROR =                         ( 128 )
}


class ModBusRtuSlaverUtils {

    //请求检查和转换
    static modbusRequestCheckAndConvert(reqBuffer) {
        const mReq=new ModbusRtuRequest();
        mReq.reqBuffer=reqBuffer;
        if(reqBuffer==null){
            mReq.status="CRC_ERR";
            return mReq;
        }
        mReq.totalByte=reqBuffer.length;
        //crc检查
        let crc = CrcUtils.CRC16(reqBuffer);
        if(crc[1]!=0||crc[0]!=0){
            mReq.status="CRC_ERR";
            return mReq;
        }
        mReq.slaveAddress = reqBuffer[0];
        mReq.funcCode = reqBuffer[1];
        mReq.startAddress = reqBuffer[2] * 256 + reqBuffer[3];
        mReq.len = reqBuffer[4] * 256 + reqBuffer[5];

        //数据地址检查,
        switch (mReq.funcCode)
        {
            //读线圈状态
            case MB_ENUM.MB_FUNC_READ_COILS:
            //写线圈
            case MB_ENUM.MB_FUNC_WRITE_SINGLE_COIL:
            {
                if (false) {
                    mReq.status = "ADDR_ERR";
                    return mReq;
                }
                break;
            }
            //读保持寄存器
            case MB_ENUM.MB_FUNC_READ_HOLDING_REGISTER:
            //写多个保持寄存器
            case MB_ENUM.MB_FUNC_WRITE_MULTIPLE_REGISTERS:
            {
                if (mReq.startAddress % 2 == 1) {
                    mReq.status = "ADDR_ERR";
                    return mReq;
                }
                break;
            }
            //读输入寄存器
            case MB_ENUM.MB_FUNC_READ_INPUT_REGISTER:
            {
                if ( mReq.startAddress % 2 == 1 )
                 {
                    mReq.status = "DATA_ERR";
                    mReq.funcCode = 0x80 | mReq.funcCode;
                    return mReq;
                }
                break;
            }
        }

        return mReq;
    }

    //读线圈
    static async  modbus_fun01(mReq)
    {
        let resBuffer=[];
        let  startAddress = mReq.startAddress;
        let  len = mReq.len;
        resBuffer[0] = mReq.slaveAddress;
        resBuffer[1] = mReq.funcCode;
        //计算返回的字节长度
        let byteLen = 0;
        if (len % 8 == 0)
        {
            byteLen =Number.parseInt( len/8);
        }
        else
        {
            byteLen =Number.parseInt(len/8)  + 1;
        }
        //返回字节数量
        resBuffer[2] = byteLen;
        for (let i = 0; i < byteLen; i++)
        {
            resBuffer[3 + i] = await ModBusTcpSlavePlugin.getV(startAddress+i);
        }
        let crc = CrcUtils.CRC16(resBuffer);
        resBuffer[3 + byteLen] = crc[0];
        resBuffer[3 + byteLen + 1] =  crc[1];
        return resBuffer;
    }

    //读取保持寄存器
    static async modbus_fun03(mReq)
    {
        let resBuffer=[];
        let  startAddress = mReq.startAddress;
        let  regLenth = mReq.len;
        let inx = 0;
        resBuffer[inx++] = mReq.slaveAddress;
        resBuffer[inx++] = mReq.funcCode;
        let byteLen = regLenth * 2;
        resBuffer[inx++] =0xff &  byteLen;
        for (let j = startAddress ; j < startAddress  + regLenth ; j++)
        {
            let v=await ModBusTcpSlavePlugin.getV(j)
            resBuffer[inx++] = 0xff & v >> 8;
            resBuffer[inx++] = 0xff & v;
        }
        let crc = CrcUtils.CRC16(resBuffer);
        resBuffer[inx++] = crc[0];
        resBuffer[inx++] =  crc[1];
        return resBuffer;
    }


    //读取输入寄存器
    static  async modbus_fun04(mReq)
    {
        let resBuffer=[];
        let  startAddress = mReq.startAddress;
        let  regLenth = mReq.len;
        let inx = 0;
        resBuffer[inx++] = mReq.slaveAddress;
        resBuffer[inx++] = mReq.funcCode;
        let byteLen = regLenth * 2;
        resBuffer[inx++] =0xff &  byteLen;
        for (let j = startAddress ; j < startAddress  + regLenth ; j++)
        {
            let v=await ModBusTcpSlavePlugin.getV(j)
            resBuffer[inx++] = 0xff & v >> 8;
            resBuffer[inx++] = 0xff & v;
        }
        let crc = CrcUtils.CRC16(resBuffer);
        resBuffer[inx++] = crc[0];
        resBuffer[inx++] =  crc[1];
        return resBuffer;
    }


    //写单个线圈
    static async  modbus_fun05(mReq)
     {
         let resBuffer=[];
         let  startAddress = mReq.startAddress;
        //写的入线圈值
         let writeValue = mReq.len;
        // u8 *resDataBuffer = modbusData.coil.buffer;
        for (let i = 0; i < mReq.totalByte; i++)
        {
            resBuffer[i] = reqBuffer[i];
        }
        //第4个字节是FF说明是置位
        if (reqBuffer[4] == 0xff)
        {
            ModBusTcpSlavePlugin.setV(startAddress,1);
        }
        else
        {
            ModBusTcpSlavePlugin.setV(startAddress,0);
        }
        return resBuffer;
    }

    //写多个保持寄存器
    static async  modbus_fun16(mReq)
    {
        let resBuffer=[];
        let  startAddress = mReq.startAddress;
        //写入的寄存器数量
        let registNum = mReq.len;
        let inx = 0;
        // u8 *resDataBuffer = modbusData.coil.buffer;
        for (let i = 0; i < 4; i++)
        {
            resBuffer[inx++] = mReq.reqBuffer[i];
        }
        resBuffer[inx++] = mReq.reqBuffer[4];
        resBuffer[inx++] = mReq.reqBuffer[5];
        let crc = CrcUtils.CRC16(resBuffer);
        resBuffer[inx++] = crc[0];
        resBuffer[inx++] =  crc[1];
        for (let j = 0 ; j <  registNum ; j++)
        {
            let addr=startAddress+j;
            let v=mReq.reqBuffer[7+j*2]*256+mReq.reqBuffer[7+j*2+1];
            ModBusTcpSlavePlugin.setV(addr,v);
        }
        return resBuffer;
    }


    /**
     * 拆分
     * @param mReq
     * @returns {[]|number[]}
     */
    static async modbusDeal(mReq){
        switch (mReq.funcCode){
            //读线圈状态
            case MB_ENUM.MB_FUNC_READ_COILS:
            {
                return ModBusRtuSlaverUtils.modbus_fun01(mReq);
            }
            //读保持寄存器
            case MB_ENUM.MB_FUNC_READ_HOLDING_REGISTER:
            {
                return ModBusRtuSlaverUtils.modbus_fun03(mReq);
            }
            //读输入寄存器
            case MB_ENUM.MB_FUNC_READ_INPUT_REGISTER:
            {
                return ModBusRtuSlaverUtils.modbus_fun04(mReq);
            }
            //写单个线圈
            case MB_ENUM.MB_FUNC_WRITE_SINGLE_COIL:
            {
                return ModBusRtuSlaverUtils.modbus_fun05(mReq);
            }
            //写多个保持寄存器
            case MB_ENUM.MB_FUNC_WRITE_MULTIPLE_REGISTERS:
            {
                return ModBusRtuSlaverUtils.modbus_fun16(mReq);
            }
            return [0];
        }
    }

}







class ModBusTcpSlavePlugin {

    static getV=(addr)=>{return 0}
    static setV=(addr,v)=>{return 0}

    constructor({com,brand,getV,setV}) {
        this.sp = new SerialPort({ path: com, baudRate: brand });
        ModBusTcpSlavePlugin.getV=getV;
        ModBusTcpSlavePlugin.setV=setV;
        this.init();
    }

    static callResolve=null;


    /**
     * 读取1到2000离散输入的状态
     * @param slaveAddress
     * @param startAddress
     * @param numberOfPoints
     * @returns {Promise<unknown>}
     */
    async readInputs(slaveAddress,  startAddress,  numberOfPoints){
        let r=  [];
        this.sp.write(new Uint8Array(r));
        return new Promise((resolve, reject) => {
            setTimeout(() => resolve("timeOut"), 1000);
            ModBusTcpSlavePlugin.callResolve=resolve;
        })
    }

   
    install(app,args){

    }


    init(){
        // 以 paused mode 监听收到的数据，需要主动读取数据
        this.sp.on('readable', async () => {
            await M.delayMs(5);
            let reqBuffer=  this.sp.read();
            if(reqBuffer==null || reqBuffer.length<5){
                return [];
            }
            let mReq =await ModBusRtuSlaverUtils.modbusRequestCheckAndConvert(reqBuffer);
            if(mReq.status==0){
                let r=await ModBusRtuSlaverUtils.modbusDeal(mReq);
                this.sp.write(new Uint8Array(r));
            }else {
                console.error(mReq.status)
            }
        });


        this.sp.on('data', (data) => {

            // console.log(data);
        });

    }

}

module.exports = ModBusTcpSlavePlugin;